const axios = require("axios");
const CryptoJS = require("crypto-js");

let _token = null;
let _userVariables = {};
let _libraryIds = null;
let lastProgressUpdate = 0;
let currentSessionId = null;
let lastReportedTime = 0;
let _currentBookId = null;
let _currentBookTracks = null;
let _totalBookDuration = 0;
let lastLoginAttempt = 0;

function generateDeviceId(username) {
  const hash = CryptoJS.SHA1(username).toString();
  return hash.substring(0, 16);
}

const COMMON_HEADERS = {
  'User-Agent': 'MusicFree',
  'Content-Type': 'application/json',
};

function getClient() {
  try {
    const currentUserVariables = env.getUserVariables();
    if (
      !currentUserVariables.url ||
      !currentUserVariables.username ||
      !currentUserVariables.password
    ) {
      return null;
    }

    if (JSON.stringify(currentUserVariables) !== JSON.stringify(_userVariables)) {
      _userVariables = currentUserVariables;
      _token = null;
      _libraryIds = null;
    }
    
    if (_userVariables.url && !_userVariables.url.startsWith('http')) {
      _userVariables.url = `http://${_userVariables.url}`;
    }
    if (_userVariables.url && _userVariables.url.endsWith('/')) {
      _userVariables.url = _userVariables.url.slice(0, -1);
    }
    
    return true;
  } catch (e) {
    return null;
  }
}

async function login() {
  if (_token) return _token;

  const now = Date.now();

  if (now - lastLoginAttempt < 5000) {
    throw new Error("登录请求过于频繁，请稍后再试。");
  }
  lastLoginAttempt = now;
  
  try {
    const { url, username, password } = _userVariables;
    const res = await axios.post(`${url}/login`, { username, password }, { headers: { 'User-Agent': COMMON_HEADERS['User-Agent'] } });
    if (res.data && res.data.user && res.data.user.token) {
      _token = res.data.user.token;
      return _token;
    }
  } catch (e) {
    _token = null;
    let errorMessage = "登录失败，请检查服务器地址、用户名和密码。";
    if (e.response && e.response.data) {
        try {
            const errorData = typeof e.response.data === 'string' ? JSON.parse(e.response.data) : e.response.data;
            if (Array.isArray(errorData) && errorData[0] && errorData[0].error) {
                errorMessage = errorData[0].error;
            } else if (errorData.error) {
                errorMessage = errorData.error;
            }
        } catch (parseError) {
            // 忽略解析错误
        }
    }
    throw new Error(errorMessage);
  }
  return null;
}

async function apiGet(endpoint, params = {}) {
  await login();
  if (!_token) {
    throw new Error("未认证，无法请求API。");
  }

  const { url } = _userVariables;
  try {
    const res = await axios.get(`${url}${endpoint}`, {
      headers: {
        ...COMMON_HEADERS,
        Authorization: `Bearer ${_token}`,
      },
      params: params,
    });
    return res.data;
  } catch (e) {
    if (e.response && e.response.status === 401) {
      _token = null;
      await login();
      if (!_token) throw new Error("重新登录失败。");
      return await apiGet(endpoint, params);
    }
    throw e;
  }
}

async function apiPatch(endpoint, data = {}) {
  await login();
  if (!_token) {
    throw new Error("未认证，无法请求API。");
  }

  const { url } = _userVariables;
  try {
    const res = await axios.patch(`${url}${endpoint}`, data, {
      headers: {
        ...COMMON_HEADERS,
        Authorization: `Bearer ${_token}`,
      },
    });
    return res.data;
  } catch (e) {
    if (e.response && e.response.status === 401) {
      _token = null;
      await login();
      if (!_token) throw new Error("重新登录失败。");
      return await apiPatch(endpoint, data);
    }
    throw e;
  }
}

async function apiPost(endpoint, data = {}) {
  await login();
  if (!_token) {
    throw new Error("未认证，无法请求API。");
  }

  const { url } = _userVariables;
  try {
    const res = await axios.post(`${url}${endpoint}`, data, {
      headers: {
        ...COMMON_HEADERS,
        Authorization: `Bearer ${_token}`,
      },
    });
    return res.data;
  } catch (e) {
    if (e.response && e.response.status === 401) {
      _token = null;
      await login();
      if (!_token) throw new Error("重新登录失败。");
        return await apiPost(endpoint, data);
      }
    throw e;
  }
}

async function getAllLibraries() {
  if (_libraryIds) {
    return _libraryIds;
  }
  const librariesData = await apiGet('/api/libraries');
  if (librariesData && librariesData.libraries) {
    _libraryIds = librariesData.libraries
    .filter(function(lib) { return lib.mediaType === 'book'; });
    return _libraryIds;
  }
  return [];
}

function stripHtml(str) {
  if (!str) return "";
  return str
  .replace(/<br\s*\/?>/gi, '\n')
  .replace(/<\/p>/gi, '\n')
  .replace(/<[^>]+>/g, '')
  .trim();
}

function formatAlbumItem(item) {
  const metadata = item.media.metadata;
  return {
    id: item.id,
    title: metadata.title || "未知标题",
    artist: metadata.authorName || "未知作者",
    artwork: `${_userVariables.url}/api/items/${item.id}/cover?token=${_token}`,
    description: stripHtml(metadata.description) || "",
  };
}

function formatArtistItem(author) {
  return {
    id: author.id,
    name: author.name,
    avatar: author.imagePath ? `${_userVariables.url}/api/authors/${author.id}/image?token=${_token}` : undefined,
    worksNum: author.numBooks,
  };
}

function formatMusicItem(track, albumItem) {
  return {
    id: `${albumItem.id}_${track.index}`,
    title: track.title,
    artist: albumItem.artist,
    album: albumItem.title,
    artwork: albumItem.artwork,
    duration: Math.round(track.duration),
    _contentUrl: track.contentUrl,
  };
}

function findTrackInfoByTime(tracks, currentTime) {
  if (!tracks || tracks.length === 0) return null;
  let cumulativeDuration = 0;
  for (const track of tracks) {
    if (currentTime >= cumulativeDuration && currentTime < cumulativeDuration + track.duration) {
      return { track: track, trackStartTime: cumulativeDuration };
    }
    cumulativeDuration += track.duration;
  }
  const lastTrack = tracks[tracks.length - 1];
  const lastTrackStartTime = cumulativeDuration - lastTrack.duration;
  return { track: lastTrack, trackStartTime: lastTrackStartTime };
}

module.exports = {
  platform: "Audiobookshelf",
  version: "1.5.1",
  author: "Ckryin",
  appVersion: ">=0.1.0",
  srcUrl: "https://gitee.com/Rrance/WP/raw/master/audiobookshelf.js",
  cacheControl: "no-cache",
  userVariables: [
    {
      key: "url",
      name: "服务器地址",
      description: "你的 Audiobookshelf 实例地址，例如：http://192.168.1.10:13378",
    },
    {
      key: "username",
      name: "用户名",
    },
    {
      key: "password",
      name: "密码",
      type: "password",
    },
  ],
  supportedSearchType: ["album", "artist"],

  async onPlaybackStateChange(...args) {
    let params;
    if (typeof args[0] === 'object' && args[0] !== null && args.length === 1) {
      params = args[0];
    } else {
      const [event, data] = args;
      params = { event, data };
    }

    if (!getClient()) {
      return;
    }
    
    const event = params.event;
    const data = params.data;
    const musicItem = params.musicItem || (data && data.musicItem);

    try {
      if (event === "track-change" || event === "stop") {
        if (currentSessionId) {
          try {
            await apiPost(`/api/session/${currentSessionId}/close`);
          } catch (e) {
            // 如果关闭会话失败，可能是会话已过期或不存在
          }
        }
        currentSessionId = null;
        lastProgressUpdate = 0;
        lastReportedTime = 0;
        _currentBookId = null;
        _currentBookTracks = null;
        _totalBookDuration = 0;
        
        if (event === "stop") {
          return;
        }
      }

      if (event === "play") {
        if (!musicItem || !musicItem.id) {
          return;
        }
        
        const libraryItemId = musicItem.id.substring(0, musicItem.id.lastIndexOf("_"));
        if (!libraryItemId) {
          return;
        }

        if (libraryItemId !== _currentBookId) {
          _currentBookId = libraryItemId;
          try {
            const itemDetails = await apiGet(`/api/items/${libraryItemId}`, { expanded: 1 });
            if (itemDetails && itemDetails.media && itemDetails.media.tracks) {
              itemDetails.media.tracks.sort(function(a, b) { return a.index - b.index; });
              _currentBookTracks = itemDetails.media.tracks;
              _totalBookDuration = _currentBookTracks.reduce(function(sum, track) { return sum + track.duration; }, 0);
            } else {
              _currentBookTracks = null;
              _totalBookDuration = 0;
            }
          } catch (e) {
            _currentBookTracks = null;
            _totalBookDuration = 0;
          }
        }

        const endpoint = `/api/items/${libraryItemId}/play`;
        
        const pluginVersion = this.version;
        const hostAppVersion = env.appVersion;
        const hostOS = env.os;

        const deviceInfo = {
          deviceId: generateDeviceId(_userVariables.username),
          clientName: "MusicFree Plugin",
          clientVersion: pluginVersion,
          model: `Host: MusicFree v${hostAppVersion} on ${hostOS}`
        };

        const sessionData = await apiPost(endpoint, {
          mediaPlayer: "MusicFree",
          deviceInfo: deviceInfo,
          forceDirectPlay: true,
          forceTranscode: false,
        });
        
        if (sessionData && sessionData.id) {
          currentSessionId = sessionData.id;
          lastReportedTime = 0; 
          lastProgressUpdate = Date.now();
        } else {
          // 如果没有返回有效的会话ID，重置状态
        }
      }
      
      if (event === "progress") {
        if (!currentSessionId && musicItem) {
          await this.onPlaybackStateChange({ event: "play", musicItem: musicItem });
          return;
        }

        if (!currentSessionId || !_currentBookTracks) return;

        const now = Date.now();
        if (now - lastProgressUpdate < 15000) {
          return;
        }
        
        const chapterCurrentTime = data && data.currentTime;

        if (!musicItem || !musicItem.id || chapterCurrentTime < 0) {
          return;
        }
        
        const trackIndexStr = musicItem.id.substring(musicItem.id.lastIndexOf("_") + 1);
        const trackIndex = parseInt(trackIndexStr, 10);
        
        let cumulativeStartTime = 0;
        for (let i = 0; i < trackIndex - 1; i++) {
          if (_currentBookTracks[i]) {
            cumulativeStartTime += _currentBookTracks[i].duration;
          }
        }
        const totalCurrentTime = cumulativeStartTime + chapterCurrentTime;
        
        if (lastReportedTime === 0 && totalCurrentTime > 1) {
          lastReportedTime = totalCurrentTime;
          lastProgressUpdate = now;
          return;
        }

        const timeListened = totalCurrentTime - lastReportedTime;

        if (timeListened <= 0 || timeListened > 20) {
          lastReportedTime = totalCurrentTime; 
          lastProgressUpdate = now;
          return;
        }

        lastProgressUpdate = now;
        
        const endpoint = `/api/session/${currentSessionId}/sync`;
        const payload = {
          currentTime: totalCurrentTime,
          duration: _totalBookDuration,
          timeListened: timeListened
        };
        
        try {
          await apiPost(endpoint, payload);
          lastReportedTime = totalCurrentTime;
        } catch (e) {
          if (e.response && (e.response.status === 404 || e.response.status === 400)) {
            currentSessionId = null;
            lastProgressUpdate = 0;
            lastReportedTime = 0;
          }
        }
      }
    } catch (e) {
      currentSessionId = null;
      lastProgressUpdate = 0;
      lastReportedTime = 0;
      _currentBookId = null;
      _currentBookTracks = null;
      _totalBookDuration = 0;
    }
  },
  
  async search(query, page, type) {
    if (!getClient()) {
      return { isEnd: true, data: [] };
    }
    
    if (page > 1) {
      return { isEnd: true, data: [] };
    }

    try {
      const libraries = await getAllLibraries();
      const libraryIds = libraries.map(function(l) { return l.id; });
      if (!libraryIds.length) {
        return { isEnd: true, data: [] };
      }

      const searchPromises = libraryIds.map(function(id) {
        return apiGet(`/api/libraries/${id}/search`, { q: query });
      });
      const resultsByLibrary = await Promise.all(searchPromises);

      if (type === "album") {
        const allBooks = resultsByLibrary.flatMap(function(result) { return result.book || []; });
        const uniqueBooks = Array.from(new Map(allBooks.map(function(item) { return [item.libraryItem.id, item.libraryItem]; })).values());
        const albums = uniqueBooks.map(formatAlbumItem);
        return { isEnd: true, data: albums };
      }
      
      if (type === "artist") {
        const allAuthors = resultsByLibrary.flatMap(function(result) { return result.authors || []; });
        const uniqueAuthors = Array.from(new Map(allAuthors.map(function(author) { return [author.id, author]; })).values());
        const artists = uniqueAuthors.map(formatArtistItem);
        return { isEnd: true, data: artists };
      }

    } catch (e) {
      return { isEnd: true, data: [] };
    }
  },

  async getAlbumInfo(albumItem) {
    if (!getClient()) return null;
    try {
      const itemDetails = await apiGet(`/api/items/${albumItem.id}`, { expanded: 1 });
      const tracks = itemDetails.media.tracks;
      if (!tracks || tracks.length === 0) return { musicList: [] };
      
      tracks.sort(function(a, b) { return a.index - b.index; });

      if (albumItem._currentTime !== undefined && albumItem._currentTime > 0) {
        const result = findTrackInfoByTime(tracks, albumItem._currentTime);
        if (result) {
          const { track: currentTrack, trackStartTime } = result;
          const startIndex = tracks.findIndex(t => t.index === currentTrack.index);
            
          if (startIndex > -1) {
            const remainingTracks = tracks.slice(startIndex);
            const musicList = remainingTracks.map(function(track, index) {
              const musicItem = formatMusicItem(track, albumItem);
              if (index === 0) {
                musicItem._currentTime = albumItem._currentTime - trackStartTime;
              }
              return musicItem;
            });
            return { isEnd: true, musicList: musicList };
          }
        }
      }

      const musicList = tracks.map(function(track) {
        return formatMusicItem(track, albumItem);
      });
      return { isEnd: true, musicList: musicList };
    } catch (e) {
      return null;
    }
  },

  async getMusicSheetInfo(sheetItem) {
    return this.getAlbumInfo(sheetItem);
  },
  
  async getArtistWorks(artistItem, page, type) {
    if (type === 'album') {
      return this.search(artistItem.name, page, 'album');
    }
  },

  async getMediaSource(musicItem) {
    if (!getClient()) return null;
    await login();
    if (!_token) return null;
    
    if (!musicItem._contentUrl) {
      try {
        const libraryItemId = musicItem.id.substring(0, musicItem.id.lastIndexOf('_'));
        const itemDetails = await apiGet(`/api/items/${libraryItemId}`, { expanded: 1 });
        const track = (itemDetails.media.tracks || []).find(function(t) { return `${libraryItemId}_${t.index}` === musicItem.id; });
        if (track && track.contentUrl) {
          musicItem._contentUrl = track.contentUrl;
        } else {
          return null;
        }
      } catch (e) {
        return null;
      }
    }
    
    return {
      url: `${_userVariables.url}${musicItem._contentUrl}?token=${_token}`,
    };
  },

  async getRecommendSheetTags() {
    if (!getClient()) return { data: [] };
    try {
      const libraries = await getAllLibraries();
      
      const pinnedTags = [
        { id: 'continue-listening', title: '继续收听' }
      ];

      if (libraries.length === 0) {
        pinnedTags.push({ id: 'no-library-found', title: '未找到有声书媒体库' });
      } else {
        const libraryTags = libraries.map(function(lib) {
          return { id: lib.id, title: lib.name };
        });
        pinnedTags.push(...libraryTags);
      }
      
      return {
        pinned: pinnedTags
      };
    } catch (e) {
      return { data: [] };
    }
  },

  async getRecommendSheetsByTag(tag, page) {
    if (!getClient()) {
      return { isEnd: true, data: [] };
    }

    try {
      if (tag.id === 'continue-listening') {
        if (page > 1) return { isEnd: true, data: [] };

        const sessionsData = await apiGet('/api/me/listening-sessions', { itemsPerPage: 50 });
        const sessions = (sessionsData.sessions || []).filter(s => s.mediaType === 'book');

        const latestSessions = new Map();
        for (const session of sessions) {
          if (!latestSessions.has(session.libraryItemId)) {
            latestSessions.set(session.libraryItemId, session);
          }
        }

        const sheets = [];
        for (const session of latestSessions.values()) {
          try {
            const itemDetails = await apiGet(`/api/items/${session.libraryItemId}`);
            const albumItem = formatAlbumItem(itemDetails);
            albumItem._currentTime = session.currentTime;
            sheets.push(albumItem);
          } catch (e) {
            // 如果获取某个书籍信息失败，则跳过
          }
        }
        return { isEnd: true, data: sheets };
      }

      if (!tag.id) {
        const libraries = await getAllLibraries();
        const libraryIds = libraries.map(function(l) { return l.id; });
        if (!libraryIds.length) return { isEnd: true, data: [] };
        
        const limitPerPage = 20;
        const promises = libraryIds.map(function(id) {
          return apiGet(`/api/libraries/${id}/items`, { 
            limit: limitPerPage, 
            page: page - 1,
            sort: 'addedAt', 
            desc: 1 
          });
        });
        const resultsByLibrary = await Promise.all(promises);
        const allItems = resultsByLibrary.flatMap(function(result) { return result.results || []; });
        
        allItems.sort(function(a, b) { return b.addedAt - a.addedAt; });
        const uniqueItems = Array.from(new Map(allItems.map(function(item) { return [item.id, item]; })).values());
        const sheets = uniqueItems.map(formatAlbumItem);

        return { isEnd: true, data: sheets };

      } else if (tag.id === 'no-library-found') {
        return { isEnd: true, data: [] };
      }
      
      const libraryId = tag.id;
      const limit = 50;
      const results = await apiGet(`/api/libraries/${libraryId}/items`, {
        limit: limit,
        page: page - 1,
        sort: 'addedAt',
        desc: 1
      });
      
      const isEnd = !results.results || results.results.length < limit;
      const sheets = (results.results || []).map(formatAlbumItem);

      return { isEnd, data: sheets };

    } catch (e) {
      return { isEnd: true, data: [] };
    }
  }
};